/**HEADER********************************************************************
* 
* Copyright (c) 2011 Freescale Semiconductor;
* All Rights Reserved
*
*************************************************************************** 
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: timer_tpm.c$
* $Version : 3.8.1.0$
* $Date    : May-11-2011$
*
* Comments:
*
*   This file contains definitions for interrupt timer utility functions
*   for TPM.
*
*END************************************************************************/

#include <mqx.h>
#include <bsp.h>
#include "timer_tpm.h"


#define TPMxSC_TOIE_MASK  0x40
#define TPMxSC_TOF_MASK   0x80
                                               

typedef struct tpmch_struct
{
  uint_8  TPMxCySC;   /* Channel Status and Control Register */
  uint_16 TPMxCyV;    /* Channel Value Register */
} TPMCH_STRUCT, _PTR_ TPMCH_STRUCT_PTR;


typedef struct tpm_struct
{
  uint_8  TPMxSC;     /* Status and Control Register */
  uint_16 TPMxCNT;    /* Counter Register */
  uint_16 TPMxMOD;    /* Counter Modulo Registers */   
  TPMCH_STRUCT CH[];  /* Channel Registers */      
} TPM_STRUCT, _PTR_ TPM_STRUCT_PTR;


/*FUNCTION*-----------------------------------------------------------------
*
* Function Name   : _tpm_init_freq
* Returned Value  : the clock rate for the timer (ns per hw tick)
* Comments        :
*   this function will set up a timer to interrupt
*
*END*---------------------------------------------------------------------*/

uint_32 _tpm_init_freq
    (
        /* [IN] the timer to initialize */
        uint_8    timer,

        /* [IN] ticks per second */
        uint_32   tickfreq,

        /* [IN] input clock speed in Hz */
        uint_32   clk,

        /* [IN] unmask the timer after initializing */
        boolean   unmask_timer
    )
{
    uint_32 rate, prescale = 0;   

    volatile TPM_STRUCT _PTR_  tpm_ptr;

    tpm_ptr = _bsp_get_tpm_base_address(timer);
    if (tpm_ptr == NULL) return 0;

    rate = (clk / tickfreq);
    while (rate > (0xFFFF+1)) {
        prescale += 1;  /* divides clock in half */
        clk >>= 1;
        rate = (clk / tickfreq);
    }

    if (prescale > 7)
        return 0; /* prescaler out of range (unexpected condition) */

    _bsp_tpm_clk_en(timer); /* enable clock to the TPM */

    /* set registers */   
    tpm_ptr->TPMxSC  = 0; /* stop the timer */
    tpm_ptr->TPMxSC &= 0; /* clear overflow flag (read register and write zero to TOF) */
    tpm_ptr->TPMxCNT = 0; /* reset the counter */

    tpm_ptr->TPMxMOD = (uint_16)(rate-1);   
    tpm_ptr->TPMxSC = ((uint_8)prescale) | MCF51XX_TPMxSC_CLK_BUSCLK | (unmask_timer ? (TPMxSC_TOIE_MASK) : 0);  
   
    /* return number of hw-ticks per MQX tick */
    return rate;
}


/*FUNCTION*-----------------------------------------------------------------
*
* Function Name   : _tpm_get_hwticks
* Returned Value  : Number of ticks
* Comments        :
*   This function will return the number of ticks elapsed since the last
* timer tick.
*
*END*---------------------------------------------------------------------*/

uint_32 _tpm_get_hwticks
    (
        /* [IN] the timer to use */
        pointer parameter
    )
{ 
    uint_32 ticks;

    volatile TPM_STRUCT _PTR_  tpm_ptr;

    tpm_ptr = _bsp_get_tpm_base_address((uint_8)parameter);
    if (tpm_ptr == NULL) return 0;
    
    ticks = (uint_16)tpm_ptr->TPMxCNT;   

    if ((tpm_ptr->TPMxSC & TPMxSC_TOF_MASK) != 0) {
        /* Another full TICK period has expired since we handled the last timer interrupt.
        We need to read the counter again, since the wrap may have
        occurred between the previous read and the checking of the overflow bit. */
        ticks = (uint_16)tpm_ptr->TPMxMOD + (uint_16)tpm_ptr->TPMxCNT + 1;
    }
 
    return ticks;
}


/*FUNCTION*-----------------------------------------------------------------
*
* Function Name   : _tpm_mask_int
* Returned Value  :
* Comments        :
*   This function will mask interrupt of given timer
*
*END*---------------------------------------------------------------------*/

void _tpm_mask_int
    (
        /* [IN] the timer to use */
        uint_8    timer
    )
{
    volatile TPM_STRUCT _PTR_  tpm_ptr;

    tpm_ptr = _bsp_get_tpm_base_address(timer);
    if (tpm_ptr == NULL) return;

    tpm_ptr->TPMxSC &= ~((uint_8)TPMxSC_TOIE_MASK);
}


/*FUNCTION*-----------------------------------------------------------------
*
* Function Name   : _tpm_unmask_int
* Returned Value  :
* Comments        :
*   This function will unmask interrupt of given timer
*
*END*---------------------------------------------------------------------*/

void _tpm_unmask_int
    (
        /* [IN] the timer to use */
        uint_8    timer
    )
{
    volatile TPM_STRUCT _PTR_  tpm_ptr;

    tpm_ptr = _bsp_get_tpm_base_address(timer);
    if (tpm_ptr == NULL) return;

    tpm_ptr->TPMxSC |= TPMxSC_TOIE_MASK;
}


/*FUNCTION*-----------------------------------------------------------------
*
* Function Name   : _tpm_clear_int
* Returned Value  :
* Comments        :
*   This function will clear interrupt flag of given timer
*
*END*---------------------------------------------------------------------*/

void _tpm_clear_int
    (
        /* [IN] the timer to use */
        uint_8    timer
    )
{
    volatile TPM_STRUCT _PTR_  tpm_ptr;

    tpm_ptr = _bsp_get_tpm_base_address(timer);
    if (tpm_ptr == NULL) return;

    tpm_ptr->TPMxSC &= ~((uint_8)TPMxSC_TOF_MASK);
}
